package no.uib.kwikktaim.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.io.IOException;
import java.net.URL;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.media.*;
import javax.media.control.FormatControl;
import javax.media.control.FrameRateControl;

/**
 * Our mediaplayer. This class includes everything you need to play a video
 *
 */
public class MediaViewer extends JPanel {

	private MainWindow mw;
	private Component video;
	private Player mediaPlayer;


	private boolean muted;
	private GainControl gc;
	private URL currentURL; // The URL we are listning to

	// Background picture
	private Image imgBackground = new javax.swing.ImageIcon(getClass().getResource("/no/uib/kwikktaim/img/background.png")).getImage();

	private float currVolume; // The volume of the medium
	private float currRate=1; // The speed of the medium

	/**
	 * Are we muted?
	 * @return True if mute
	 */
	public boolean isMuted() {
		return muted;
	}


	/**
	 * The window where media is played
	 * @param windownumber the number
	 */
	public MediaViewer(MainWindow mw) {
		this.mw = mw;


		this.setPreferredSize(new Dimension(300,200));
		muted = false;
	}


	/**
	 * Test if it is a video
	 * @return true if the medium is a video
	 */
	public boolean isVideo() {
		if(video == null)
			return false;

		return true;
	}


	/**
	 * Play a media file
	 * @param mediaURL the URL to the file!
	 */
	public void play(URL mediaURL) {
		Manager.setHint( Manager.LIGHTWEIGHT_RENDERER, true );
		currentURL = mediaURL;
		if(mediaPlayer != null) {
			mediaPlayer.stop();
			if(video != null)
				this.remove(video);
		}

		// Try to open the media
		try {
			this.setLayout(new BorderLayout());
			if(mediaURL == null) return; //Makes sure you have media loaded
			mediaPlayer = Manager.createRealizedPlayer( mediaURL );
			gc = mediaPlayer.getGainControl();
			gc.setLevel(currVolume);
			gc.setMute(muted);
			setSpeed(getSpeed());
			video = mediaPlayer.getVisualComponent();
			if(video != null) {
				this.add(video,BorderLayout.CENTER);
				mw.pack();
			}


			mediaPlayer.start();

		} catch (NoPlayerException e) {
			JOptionPane.showMessageDialog(this,"Unable to load file '" + mediaURL + "'!","Fatal error 101 SOS",JOptionPane.ERROR_MESSAGE);
		} catch (CannotRealizeException e) {
			JOptionPane.showMessageDialog(this,"Unable to handle format!","Fatal error 101 SOS",JOptionPane.ERROR_MESSAGE);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this,"Unable to load file '" + mediaURL + "'!","Fatal error 101 SOS",JOptionPane.ERROR_MESSAGE);
		}

		setVisible(true);
	}

	/**
	 * Reloads the medium
	 */
	public void reloadVideo() {
		this.remove(video);
		this.add(video, BorderLayout.CENTER);
	}

	/**
	 * Where we are
	 * @return how many seconds we are in the media
	 */
	public double getTime() {
		if(mediaPlayer == null)
			return 0;
		return mediaPlayer.getMediaTime().getSeconds();
	}

	/**
	 * Where in the media we should be
	 * @param time time in seconds
	 */
	public void setTime(double time) {
		if(mediaPlayer == null)
			return;
		mediaPlayer.setMediaTime(new Time(time));
	}

	/**
	 * Overrides so we can add a background picture
	 */
	public void paintComponent(Graphics g) {
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, 10000, 10000);
		g.drawImage(imgBackground, 0, 0, null);
	}

	/**
	 * Get the medium information
	 */
	public String toString() {

		if(mediaPlayer == null)
			return "No media loaded.";

		Control[] fc = mediaPlayer.getControls();

		FormatControl format = null;
		FrameRateControl frameRate = null;

		for (Control control : fc) {
			if(control instanceof  FormatControl) {
				if(format == null) format = (FormatControl) control;
			}
			if(control instanceof   FrameRateControl) {
				 frameRate = ( FrameRateControl) control;
			}
		}


		if(video == null)
			return  "Type of media: Audio\n" +
					"Duration: " + getTotalTime() + " seconds\n" +
					"Encoding: " + format.getFormat().getEncoding() + "\n";

		else {
			return  "Type of media: Video\n" +
					"Duration: " + getTotalTime() + " seconds\n" +
					"Resolution: " + (int)video.getPreferredSize().getWidth() + "x" + (int)video.getPreferredSize().getHeight() + "\n" +
					"Encoding: " + format.getFormat().getEncoding() + "\n" +
					"Frame rate: " + frameRate.getFrameRate();
		}
	}

	/**
	 * Total duration
	 * @return total duration in seconds
	 */
	public int getTotalTime() {
		if(mediaPlayer == null)
			return 0;
		return (int) mediaPlayer.getDuration().getSeconds();
	}

	/**
	 * @return the url to the current medium
	 */
	public URL getCurrentURL() {
		return currentURL;
	}

	/**
	 * Stops the medium and reset the time
	 */
	public void stop() {
		if(mediaPlayer != null) {
			mediaPlayer.stop();
			mediaPlayer.setMediaTime(new Time(0.0));
			if(video != null)
				this.remove(video);
		}
	}

	/**
	 * Starts the medium
	 */
	public void play() {
		if(mediaPlayer != null) {
			mediaPlayer.start();
		}
	}

	/**
	 * Stops the medium
	 */
	public void pause() {
		if(mediaPlayer != null) {
			mediaPlayer.stop();
		}
	}

	/**
	 * Sets the volume
	 * @param newVolume the new volume
	 */
	public void changeVolume(int newVolume) {
		currVolume = (float)(newVolume / 128.0);

		if(gc != null)
			gc.setLevel(currVolume);
	}

	/**
	 * Retrive the volume
	 * @return the mediums volume
	 */
	public int getVolume() {
		return (int)(currVolume*100);
	}

	/**
	 * Toggle mute on and off
	 */
	public void mute() {
		muted = !muted;
		if(gc != null)
			gc.setMute(muted);
	}

	/**
	 * Returns the mediums video component if it has one
	 * @return the video
	 */
	public Component getVisualComponent() {
		return video;
	}

	/**
	 * Retrives the mediaplayer for external use
	 * @return the player
	 */
	public Player getMediaPlayer() {
	    return mediaPlayer;
	}


	/**
	 * Sets the player
	 * @param mediaPlayer the mediaplayer we want to add
	 */
	public void setMediaPlayer(Player mediaPlayer) {
	    this.mediaPlayer = mediaPlayer;
	}


	/**
	 * Set the speed of the medium
	 * @param currRate The relative speed. 1 is normal speed
	 */
	public void setSpeed(float currRate) {

		this.currRate = currRate;
		if(mediaPlayer!=null) {
			int priorstate = mediaPlayer.getState();
			if (priorstate == Controller.Started)
			{
				mediaPlayer.stop();
			}
			mediaPlayer.setRate(currRate);
			mediaPlayer.start();
		}
	}


	/**
	 * Get the speed of the medium
	 * @return the relative speed of medium. 1 is normal speed
	 */
	public float getSpeed() {
		return currRate;
	}

}
